/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.dandsoft.mavrep.web.controller.repository;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Arrays;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.io.IOUtils;
import org.dandsoft.mavrep.manager.ArtifactManager;
import org.dandsoft.mavrep.data.ArtifactName;
import org.dandsoft.mavrep.data.Resource;
import org.dandsoft.mavrep.data.InputStreamResource;
import org.dandsoft.mavrep.web.ErrorModel;
import org.dandsoft.mavrep.web.ServletRequestResource;
import org.dandsoft.mavrep.web.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 *
 * @author fin
 */
@Controller
public class Maven2RepositoryController {

    private static final Log LOG = LogFactory.getLog(Maven2RepositoryController.class);

    private static final String RESOURCE_PATTERN = "/**/*.*";
    private static final String METADATA_PATTERN = "/**/maven-metadata.*";
    @Autowired
    private ArtifactManager artifactManager;

    @RequestMapping(value = METADATA_PATTERN,
    method = {RequestMethod.GET, RequestMethod.POST})
    public void getMetadataResource(HttpServletRequest request, HttpServletResponse response)
            throws IOException, IllegalArtifactPathException {
        if (LOG.isInfoEnabled()) {
            LOG.info(createLog(request));
        }
        doGetResource(getArtifactNameNoVersion(request), getResourceName(request), response);
    }



    @RequestMapping(value = RESOURCE_PATTERN,
    method = {RequestMethod.GET, RequestMethod.POST})
    public void getResource(HttpServletRequest request, HttpServletResponse response)
            throws IOException, IllegalArtifactPathException {
        if (LOG.isInfoEnabled()) {
            LOG.info(createLog(request));
        }
        doGetResource(getArtifactName(request), getResourceName(request), response);
    }

    private void doGetResource(ArtifactName artifactName, String resourceName,
            HttpServletResponse response) throws IOException {
        Resource resource = artifactManager.getResource(artifactName, resourceName);
        if (resource == null) {
            response.sendError(HttpServletResponse.SC_NO_CONTENT);
        } else {
            response.setContentLength(resource.getSize());
            OutputStream out = response.getOutputStream();
            InputStream input = ((InputStreamResource) resource).getInputStream();
            try {
                IOUtils.copy(input, out);
            } finally {
                IOUtils.closeQuietly(input);
            }
        }
    }

    @RequestMapping(value = RESOURCE_PATTERN, method = RequestMethod.PUT)
    public void putResource(final HttpServletRequest request, HttpServletResponse response)
            throws IOException, IllegalArtifactPathException, ContentLengthNotFoundException  {
        if (LOG.isInfoEnabled()) {
            LOG.info(createLog(request));
        }
        doPutResource(getArtifactName(request),  getResourceName(request), request, response);
    }

    @RequestMapping(value = METADATA_PATTERN, method = RequestMethod.PUT)
    public void putMetadataResource(HttpServletRequest request, HttpServletResponse response)
            throws IOException, IllegalArtifactPathException, ContentLengthNotFoundException {
        if (LOG.isInfoEnabled()) {
            LOG.info(createLog(request));
        }
        doPutResource(
                getArtifactNameNoVersion(request), getResourceName(request), request, response);
    }

    @ExceptionHandler(ContentLengthNotFoundException.class)
    public ModelAndView exceptionHandler(ContentLengthNotFoundException e, HttpServletResponse response){
        if (LOG.isWarnEnabled()) {
            LOG.warn("", e);
        }
        return createError(HttpServletResponse.SC_LENGTH_REQUIRED, e, response);
    }

    @ExceptionHandler(IllegalArtifactPathException.class)
    public ModelAndView exceptionHandler(IllegalArtifactPathException e, HttpServletResponse response) {
        if (LOG.isWarnEnabled()) {
            LOG.warn("", e);
        }
        return createError(HttpServletResponse.SC_BAD_REQUEST, e, response);
    }

    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(Exception e, HttpServletResponse response) {
        if (LOG.isErrorEnabled()) {
            LOG.error("", e);
        }
        return createError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e, response);
    }

    private ErrorModel createError(int statusCode, Throwable t, HttpServletResponse response) {
        response.setStatus(statusCode);
        return new ErrorModel(statusCode, t);
    }

    private void doPutResource(ArtifactName artifactName, String resourceName,
            HttpServletRequest request, HttpServletResponse response)
            throws IOException, ContentLengthNotFoundException {
        
        if (request.getContentLength() < 0) {
            throw new ContentLengthNotFoundException();
        }
        artifactManager.
                persistContent(artifactName, resourceName, new ServletRequestResource((request)));
    }

    private static String getResourceName(HttpServletRequest request) {
        final String pathInfo = request.getPathInfo();
        return pathInfo.substring(pathInfo.lastIndexOf('/') + 1, pathInfo.length());
    }

    private static ArtifactName getArtifactName(HttpServletRequest request)
            throws IllegalArtifactPathException {
        final String[] c = request.getPathInfo().split("/");
        if (c.length < 5) {
            throw new IllegalArtifactPathException((request.getPathInfo()));
        }
        final String versionStr = c[c.length - 2];
        final String artifactId = c[c.length - 3];
        final String groupId = StringUtils.concatenate(c, 1, c.length - 4, "", ".", "");
        return new ArtifactName(groupId, artifactId, versionStr);
    }

    private static ArtifactName getArtifactNameNoVersion(HttpServletRequest request)
            throws IllegalArtifactPathException {
        final String[] c = request.getPathInfo().split("/");
        if (c.length < 4) {
            throw new IllegalArtifactPathException((request.getPathInfo()));
        }
        final String artifactId = c[c.length - 2];
        final String groupId = StringUtils.concatenate(c, 1, c.length - 3, "", ".", "");
        return new ArtifactName(groupId, artifactId, null);
    }

    private static String createLog(HttpServletRequest request) {
        return request.getRequestURL() + (request.getQueryString() != null ?
            "?" + request.getQueryString() : "");
    }

    public ArtifactManager getArtifactManager() {
        return artifactManager;
    }

    public void setArtifactManager(ArtifactManager artifactManager) {
        this.artifactManager = artifactManager;
    }
}
